# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.


from odoo import http, api
from odoo.http import request
from odoo import registry as registry_get
from odoo.service import security

from odoo import SUPERUSER_ID, _

import random

from . import crypt
from . import model2
Model2 = model2.Model2


import logging
_logger = logging.getLogger(__name__)


class JsonApi(http.Controller):
    @http.route('/api/test1',type='json', auth='none',cors='*',csrf=False)
    def test1(self,**kw):
        print('hello')
        return "hello!"


    @http.route('/api/logout2',type='json', auth='user', cors='*', csrf=False )
    @crypt.decode
    def destroy2(self):
        self._destroy()
        

    @http.route('/api/login2',type='json', auth='none', cors='*', csrf=False )
    @crypt.decode
    def login2(self,db,login,password, **kw):
        return self._login(db,login,password, **kw )

    @http.route('/api/call2',type='json', auth='user',cors='*',csrf=False)
    @crypt.decode
    def api_call2(self,model,method, args,kwargs,sudo=None):
        return self._api_call( model, method, args,kwargs )


    @http.route(['/api/call', '/odoo/api/call'], type='json', auth='user',cors='*',csrf=False)
    def api_call(self,model,method, args,kwargs,sudo=None):
        return self._api_call( model, method, args,kwargs )

    @http.route(['/api/login','/odoo/api/login'],type='json', auth='none', cors='*', csrf=False )
    def login(self,db,login,password, **kw):
        return self._login(db,login,password, **kw )

    @http.route(['/api/userinfo','/odoo/api/userinfo'],type='json', auth='user', cors='*', csrf=False )
    def userinfo(self):
        return self._userinfo()


    @http.route(['/api/logout','/odoo/api/logout'],type='json', auth='user', cors='*', csrf=False )
    def destroy(self):
        self._destroy()

    @http.route(['/api/sms/login'],type='json', auth='none', cors='*', csrf=False )
    def sms_login(self, db, mobile, code):
        return self._sms_login(db, mobile, code)

    @http.route(['/api/sms/resetpsw'],type='json', auth='none', cors='*', csrf=False )
    def sms_resetpsw(self, db, mobile, code, password):
        return self._sms_resetpsw(db, mobile, code, password)

    @http.route(['/api/sms/register'],type='json', auth='none', cors='*', csrf=False )
    def register(self, db, mobile, code, login, password):
        return self._sms_register(db, mobile, code, login, password)

    @http.route(['/api/sms/send'],type='json', auth='none', cors='*', csrf=False )
    def sms_send(self, db, mobile, tosend=None):
        _logger.info('call sms_send with %s, %s,%s,', db, mobile , tosend)
        return self._sms_send(db, mobile, tosend)

    @http.route(['/api/sms/back'],type='json', auth='none', cors='*', csrf=False )
    def sms_back(self, db, mobile):
        return self._sms_back(db, mobile)


    def _api_call(self,model,method, args,kwargs):
        _logger.info('model %s call %s with %s, %s', model,method, args,kwargs)
        odoo_model = request.env[model]

        # fields_get2, return multi model
        # search_count2 and search_read2, domain is dict
        # search_read2, read2, fields is dict
        # 2019-11-27 TBD,   getOption only for m2o? 

        if method in [
            'test_function', 'new2',
            'fields_get2', 'search_count2', 'search_read2', 'read2', 
            'create2', 'write2', 'create', 'write',
            'get_options',
            'wizard_create','wizard_submit','report_print',
            ]:

            ret = {
                'test_function':   Model2.test_function,
                'new2':   Model2.new,
                # 'onchange':   Model2.onchange,
                'fields_get2':   Model2.fields_get,
                'search_count2': Model2.search_count,
                'search_read2':  Model2.search_read,
                'read2':         Model2.read,
                'create2':       Model2.create2,
                'write2':        Model2.write2,
                'create':        Model2.create,
                'write':         Model2.write,
                
                'get_options':   Model2.get_options,
                'wizard_create':   Model2.wizard_create,
                'wizard_submit':   Model2.wizard_submit,
                'report_print':    Model2.report_print,

            }[method](odoo_model, *args, **kwargs)

            return ret

        # if method == 'create2':
        #     method = 'create'
        # elif method == 'write2':
        #     method = 'write'

        return api.call_kw(odoo_model, method, args, kwargs)


    def _login(self,db,login,password, **kw):
        _logger.info('call login with %s, %s, %s', db,login,password )
        request.session.authenticate(db, login, password)
        request.session.rotate = False

        return Auth.get_sessioninfo()

    def _userinfo(self,  **kw):
        _logger.info('call _userinfo '  )
        return Auth.get_sessioninfo()

    def _destroy(self):
        # 安装销售模块后, utm 模块 会找 db
        request.session.logout(keep_db=True)

    
    def _sms_send(self, db, mobile, tosend):
        _logger.info('call sms with %s, %s', db, mobile )
        # 使用验证码登录时, 先检查 电话号码是否存在, 不存在则不发
        # 使用验证码注册时, 若电话号码已存在, 则? TBD 2020-4-27

        domain = [('mobile','=', mobile)]
        registry = registry_get(db)
        context = {}
        with registry.cursor() as cr:
            env = api.Environment(cr, SUPERUSER_ID, context)
            User = env['res.users']
            user = User.search(domain)
            print('_sms_send,', user, user.id, user.login, user.name)

            if not ( user or tosend ):
                return None

        request.session.auth_login = {
            'db': db,
            'mobile': mobile,
            'code': str(int( ( random.random()  + 1 ) * 10000 ))[1:]
        }

        print('request.session._sms_send,', request.session.auth_login)

        # then call sms api to send msg

        return True


    def _sms_back(self, db, mobile):
        auth_login = request.session.auth_login or {}
        # print('request.session._sms_back, server', request.session.auth_login)
        # print('request.session._sms_back, client', db, mobile)
        if isinstance(auth_login, dict) and auth_login.get('db') == db \
            and auth_login.get('mobile') == mobile:
            # print('request.session._sms_back, ok', auth_login.get('code') )

            return auth_login.get('code')
        return None

    def _check_sms_code(self, db, mobile, code):
        auth_login = request.session.auth_login
        if not auth_login:
            return None
        if not isinstance(auth_login, dict):
            return None
        if auth_login.get('mobile') != mobile:
            return None
        if auth_login.get('code') != code:
            return None
        return True

    def _sms_register(self, db, mobile, code, login, password):
        _logger.info('call _sms_register with %s, %s', db, mobile )
        if not self._check_sms_code(db, mobile, code):
            return None

        ret = Auth.register(db, mobile, login, password)

        return ret


    def _sms_resetpsw(self, db, mobile, code, password):
        _logger.info('call _sms_resetpsw with %s, %s', db, mobile )
        if not self._check_sms_code(db, mobile, code):
            return None

        domain = [('mobile','=', mobile)]
        ret = Auth.reset_password(db, domain, password)
        
        _logger.info('call _sms_resetpsw return:  %s', ret )

        return ret

    def _sms_login(self, db, mobile, code):
        _logger.info('call _sms_login with %s, %s', db, mobile )
        if not self._check_sms_code(db, mobile, code):
            return None

        domain = [('mobile','=', mobile)]

        uid = Auth.authenticate(db, domain)
        if uid:
            return Auth.get_sessioninfo()

        return None


class Auth(object):
    @classmethod
    def get_sessioninfo(cls):
        session_info = request.env['ir.http'].session_info()
        # for odoo 13, session_id is not in session_info
        if not session_info.get('session_id'):
            session_info['session_id'] = request.session.sid

        print('xxxxxx, session_info,', session_info)
        return session_info


    @classmethod
    def register(cls, db, mobile, login, password):
        registry = registry_get(db)
        context = {}
        with registry.cursor() as cr:
            env = api.Environment(cr, SUPERUSER_ID, context)
            User = env['res.users']
            ret = User.create({
                'mobile': mobile,
                'email': login,
                'name': login,
                'login': login,
                'password': password
            })

            return ret


    @classmethod
    def reset_password(cls, db, domain, password):
        registry = registry_get(db)
        context = {}
        with registry.cursor() as cr:
            env = api.Environment(cr, SUPERUSER_ID, context)
            User = env['res.users']
            user = User.search(domain)
            ret = user.write({
                'password': password
            })

            return ret


    @classmethod
    def authenticate(cls, db, domain):
        registry = registry_get(db)
        context = {}

        with registry.cursor() as cr:
            env = api.Environment(cr, SUPERUSER_ID, context)
            User = env['res.users']
            user = User.search(domain)
            if not user:
                return None

            user = user.with_user(user)
            user._update_last_login()

            return _authenticate(db, user.login, user.id)

    
def _authenticate( db, login, uid):
        self = request.session
        self.rotate = False
        self.db = db
        self.uid = uid
        self.login = login
        self.session_token = uid and security.compute_session_token(self, request.env)
        request.uid = uid
        request.disable_db = False

        if uid: self.get_context()
        return uid

